package cn.wolfcode.car.business.service.impl;

import cn.wolfcode.car.business.domain.BpmnInfo;
import cn.wolfcode.car.business.mapper.BpmnInfoMapper;
import cn.wolfcode.car.business.query.BpmnInfoQuery;
import cn.wolfcode.car.business.service.IBpmnInfoService;
import cn.wolfcode.car.common.base.page.TablePageInfo;
import cn.wolfcode.car.common.config.SystemConfig;
import cn.wolfcode.car.common.exception.BusinessException;
import cn.wolfcode.car.common.util.Convert;
import cn.wolfcode.car.common.util.file.FileUploadUtils;
import com.github.pagehelper.PageHelper;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.apache.commons.compress.compressors.FileNameUtil;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import oshi.util.FileUtil;

import java.io.*;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipInputStream;

@Service
@Transactional
public class BpmnInfoServiceImpl implements IBpmnInfoService {

    @Autowired
    private BpmnInfoMapper bpmnInfoMapper;

    //本地仓库对象
    @Autowired
    private RepositoryService repositoryService;


    @Override
    public TablePageInfo<BpmnInfo> query(BpmnInfoQuery qo) {
        PageHelper.startPage(qo.getPageNum(), qo.getPageSize());
        return new TablePageInfo<BpmnInfo>(bpmnInfoMapper.selectForList(qo));
    }


    @Override
    public void save(BpmnInfo bpmnInfo) {
        bpmnInfoMapper.insert(bpmnInfo);
    }

    @Override
    public BpmnInfo get(Long id) {
        return bpmnInfoMapper.selectByPrimaryKey(id);
    }


    @Override
    public void update(BpmnInfo bpmnInfo) {
        bpmnInfoMapper.updateByInfo(bpmnInfo);
    }

    @Override
    public void deleteBatch(String ids) {
        Long[] dictIds = Convert.toLongArray(ids);
        for (Long dictId : dictIds) {
            bpmnInfoMapper.deleteByPrimaryKey(dictId);
        }
    }

    @Override
    public List<BpmnInfo> list() {
        return bpmnInfoMapper.selectAll();
    }

    @Override
    public String upload(MultipartFile file) {

        //我们需要返回，存放在磁盘中的路径
        //获取上传文件名：getOriginalFilename();
        //获取文件上传的后缀名：FilenameUtils.getExtension(filename);

        //判断文件是否为空
        if (file != null && file.getSize() > 0){

            //获取上传文件名：getOriginalFilename();
            String filename = file.getOriginalFilename();

            //获取文件上传的后缀名
            String exs = FilenameUtils.getExtension(filename);

            //判断是压缩包还是，bpmn文件
            if ("zip".equalsIgnoreCase(exs) || "bpmn".equalsIgnoreCase(exs)){

                try {
                    //存入到磁盘中，通过配置文件中，存放到指定位置
                    String path = FileUploadUtils.upload(SystemConfig.getUploadPath(), file);
                    return path;
                } catch (IOException e) {
                    e.printStackTrace();
                   throw new BusinessException("文件上传失败");
                }
            }else {
                throw new BusinessException("流程定义文件仅支持 bpmn 和 zip 格式！");
            }
        }else {
            throw  new BusinessException("不可以上传空文件");
        }
    }

    @Override
    public void deploy(String bpmnPath, String bpmnType, String info) throws FileNotFoundException {

        //目的：流程文件部署，传递过来的参数不完整，需要处理
        //流程定义名称，部署流程id，流程定义id，流程定义的key，部署时间，

        //2：部署流程
        //将路径转换为小写，方便比较
        String lowStr = bpmnPath.toLowerCase();


        //将输入流的文件，文件流： 读取之前上传的流程文件
        //SystemConfig.getProfile() 获取文件上传的路径
        FileInputStream stream = new FileInputStream(new File(SystemConfig.getProfile(), bpmnPath));

        Deployment deploy = null;

        //判断上传文件的后缀名 endsWith 判断用于测试字符串是否以指定的后缀结束
        if (lowStr.endsWith("zip")){
            //上传文件的后缀名为 zip
            //部署流程的文件,通过本地仓库对象RepositoryService
             deploy = repositoryService.createDeployment()
                    .addZipInputStream(new ZipInputStream(stream))
                    .deploy();
        }else  if (lowStr.endsWith("bpmn")){
            deploy =  repositoryService.createDeployment()
                    //参数：         资源名称，流程文件流
                    .addInputStream(bpmnPath,stream)
                    .deploy();
        }

        if (deploy == null){
            throw  new BusinessException("部署失败");
        }

        //创建表，创建流程定义对象
        //流程定义名称，部署流程id，流程定义id，流程定义的key，部署时间，
        BpmnInfo bpmnInfo = new BpmnInfo();

        bpmnInfo.setInfo(info);
        bpmnInfo.setBpmnPath(bpmnPath);
        bpmnInfo.setBpmnType(bpmnType);
        bpmnInfo.setDeploymentId(deploy.getId());
        bpmnInfo.setDeployTime(deploy.getDeploymentTime());

        //获取流程定义对象，通过流程部署对象获取
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .latestVersion()
                .singleResult();
        //部署对象无法获取name，使用定义对象name，（当初画流程图的时候指定的名称）
        bpmnInfo.setBpmnName(processDefinition.getName());
        bpmnInfo.setActProcessId(processDefinition.getId());
        bpmnInfo.setActProcessKey(processDefinition.getKey());

        //进行保存操作
        bpmnInfoMapper.insert(bpmnInfo);


    }


    @Override
    public void delete(Long id) {

        //删除，需要删除流程文件，流程部署，流程定义

        //查询流程定义对象
        BpmnInfo bpmnInfo = bpmnInfoMapper.selectByPrimaryKey(id);

        //通过本地仓库对象，删除部署对象，根据部署id,及是否使用次联级删除
        repositoryService.deleteDeployment(bpmnInfo.getDeploymentId(),true);

        //流程文件删除
        //获取磁盘中的文件
        File file = new File(SystemConfig.getProfile(), bpmnInfo.getBpmnPath());
        if (file.exists()){
            //如果文件存在，删除操作
            file.delete();
        }

        //删除审核流程定义对象
        bpmnInfoMapper.deleteByPrimaryKey(id);

    }

    @Override
    public InputStream getResoucceByType(String deploymentId, String type) {

        //进行资源的查看
        //通过本地仓库对象，获取流程定义对象(流程定义对象可以不用)
        /*ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploymentId)
                .latestVersion()
                .singleResult();*/

        BpmnInfo bpmnInfo = bpmnInfoMapper.selectBydeploymentId(deploymentId);

        //如果点击流程文件，传递过来的类型为xml，
        if ("xml".equals(type)){
            //根据 流程定义对象，返回一个磁盘路径给输入流，然后程序会去磁盘文件中读取流程文件
            return repositoryService.getResourceAsStream(deploymentId,bpmnInfo.getBpmnPath());

        }else if ("png".equals(type)){

            BpmnModel model = repositoryService.getBpmnModel(bpmnInfo.getActProcessId());
            ProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();
            //generateDiagram(流程模型,需要高亮的节点,需要高亮的线条,后面三个参数都表示是字体)
            InputStream inputStream = generator.generateDiagram(model, Collections.EMPTY_LIST, Collections.EMPTY_LIST,
                    "宋体","宋体","宋体");
            return inputStream;
        }
        return null;
    }

    @Override
    public BpmnInfo queryType(String carPackage) {

        return bpmnInfoMapper.queryType(carPackage);
    }


}
